﻿using Newtonsoft.Json;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Media3D;
using System.Windows;


namespace Common.ViewModels
{
    /// <summary>
    /// 在世界坐标下的描述
    /// </summary>
    [Serializable]
    [JsonObject(MemberSerialization.OptOut)]
    public class Point3D : ViewModelBase
    {

        private double m_X;

        /// <summary>
        /// X
        /// </summary>
        public double X
        {
            get => m_X;
            set
            {
                if (m_X != value)
                {
                    m_X = value;
                    this.RaisePropertyChanged();
                }
            }
        }

        private double m_Y;

        /// <summary>
        /// Y
        /// </summary>
        public double Y
        {
            get => m_Y;
            set
            {
                if (m_Y != value)
                {
                    m_Y = value;
                    this.RaisePropertyChanged();
                }
            }
        }

        private double m_Z;

        /// <summary>
        /// Z
        /// </summary>
        public double Z
        {
            get => m_Z;
            set
            {
                if (m_Z != value)
                {
                    m_Z = value;
                    this.RaisePropertyChanged();
                }
            }
        }

        private Point m_Point2D = new Point(0, 0);

        [JsonIgnore]
        public Point Point2D
        {
            get => m_Point2D;
            set
            {
                if (m_Point2D != value)
                {
                    m_Point2D = value;
                    this.RaisePropertyChanged();
                }

            }
        }

        //[JsonIgnore]
        //[Reactive] public Point Point2D { get; set; } = new Point(0, 0);


        /// <summary>
        /// Point3D
        /// </summary>
        public Point3D()
        {
            UpdatePoint2D();
            //Point2D.
        }

        /// <summary>
        /// Point3D
        /// </summary>
        public Point3D(double x, double y, double z)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
            UpdatePoint2D();
        }

        public void UpdatePoint2D(bool isUpdate = true)
        {
            m_IDisposable.Add(this.WhenAnyValue(x => x.X, y => y.Y).Subscribe(x =>
            {
                m_Point2D.X = this.X;
                m_Point2D.Y = this.Y;
                this.RaisePropertyChanged(nameof(Point2D));
                //Point2D = new Point(X, Y);
            }));

            //if (isUpdate)
            //{
            //   
            //   
            //   
            //   
            //}


        }

        /// <summary>
        /// 3D
        /// </summary>
        /// <param name="point3D"></param>
        public Point3D(System.Windows.Media.Media3D.Point3D point3D)
        {
            this.X = point3D.X;
            this.Y = point3D.Y;
            this.Z = point3D.Z;
        }

        public void Update(Point3D point3D)
        {
            this.X = point3D.X;
            this.Y = point3D.Y;
            this.Z = point3D.Z;
        }

        public void Update(Vector3D point3D)
        {
            this.X = point3D.X;
            this.Y = point3D.Y;
            this.Z = point3D.Z;
        }

        /// <summary>
        /// 连接两个点
        /// </summary>
        /// <param name="point3D"></param>
        public void Union(Point3D point3D)
        {
            this.WhenAnyValue(x => X, y => Y, z => Z).Subscribe(x =>
            {
                this.Update(point3D);
            });
        }

        /// <summary>
        /// 当前3D
        /// </summary>
        /// <param name="point3D"></param>
        public static implicit operator Point3D(System.Windows.Media.Media3D.Point3D point3D)
        {
            return new Point3D(point3D);
        }

        public static Point3D operator +(Point3D p1, Point3D p2)
        {
            Point3D point3D = new Point3D();
            point3D.X = p1.X + p2.X;
            point3D.Y = p1.Y + p2.Y;
            point3D.Z = p1.Z + p2.Z;
            return point3D;
        }

        /// <summary>Subtracts a <see cref="T:System.Windows.Media.Media3D.Vector3D" /> structure from a <see cref="T:System.Windows.Media.Media3D.Point3D" /> structure and returns the result as a <see cref="T:System.Windows.Media.Media3D.Point3D" /> structure.</summary>
        /// <param name="point">The <see cref="T:System.Windows.Media.Media3D.Point3D" /> structure from which to subtract <paramref name="vector" />.</param>
        /// <param name="vector">The <see cref="T:System.Windows.Media.Media3D.Vector3D" /> structure to subtract from <paramref name="point" />.</param>
        /// <returns>The difference between <paramref name="point" /> and <paramref name="vector" />.</returns>
        public static Point3D Subtract(Point3D point, Point3D vector)
        {
            return new Point3D(point.X - vector.X, point.Y - vector.Y, point.Z - vector.Z);
        }

        /// <summary>
        /// 获取系统的3D点
        /// </summary>
        /// <returns></returns>
        public System.Windows.Media.Media3D.Point3D GetMedia3D()
        {
            System.Windows.Media.Media3D.Point3D point3D = new(X, Y, Z);
            return point3D;
        }

        public double GetDistance(Point3D point3D)
        {
            double distance = 0;
            Point3D sub = Subtract(this,point3D);
           return  Math.Sqrt(sub.X * sub.X + sub.Y * sub.Y + sub.Z * sub.Z);
        }
    }
}
